#pragma once
#include "GameObject.h"
#include "../SGD Wrappers/SGD_Handle.h"
#include "../SGD Wrappers/SGD_Color.h"
#include "AnimationTimeStamp.h"
#include "../SGD Wrappers/SGD_Listener.h"
#include "AnimationSystem.h"

class Emitter;

struct CollisionData
{
	SGD::Rectangle	collidedRect;
	SGD::Point		pastPosition;
	std::string		tileType;
};


class MovingObject : public GameObject, public SGD::Listener
{
public:

	MovingObject();
	virtual ~MovingObject();

	enum MovingObjectType { OBJ_BASE, OBJ_PLAYER, OBJ_ENEMY, OBJ_BULLET, OBJ_BOSS };


	/**********************************************************/
	// Interface:
	//	- virtual functions for children classes to override
	virtual void	Update(float elapsedTime)		override;
	virtual void	Render(void)					override;

	virtual SGD::Rectangle GetRect(void)	const			override;
	virtual SGD::Rectangle GetActiveRect(void)	const override;

	virtual int		GetType(void)	const			override	{ return OBJ_BASE; }
	virtual void	HandleCollision(GameObject* pOther)	override;
	void			HandleRightCollision(MovingObject* other, SGD::Rectangle intersection);
	void			HandleLeftCollision(MovingObject* other, SGD::Rectangle intersection);
	void			HandleUpCollision(MovingObject* other, SGD::Rectangle intersection);
	void			HandleDownCollision(MovingObject* other, SGD::Rectangle intersection);
	virtual void	HandleEvent(const SGD::Event* pEvent) override;
	// Children classes CANNOT override a 'final' method.
	virtual void	AddRef(void)				final;
	virtual void	Release(void)				final;

	/**********************************************************/
	// Accessors:
	SGD::HTexture		GetImage(void) const			{ return m_hImage; }
	SGD::Point			GetPastPosition(void) const		{ return pastPosition; }
	SGD::Vector			GetVelocity(void) const			{ return m_vtVelocity; }
	float				GetRotation(void) const			{ return m_fRotation; }
	int					GetMaxSpeed(void) const			{ return m_iMaxSpeed; }
	float				GetAttackRate(void) const		{ return m_fAttackRate; }
	int					GetHealth(void) const			{ return m_iHealth; }
	int					GetMaxHealth(void) const		{ return m_iMaxHealth; }
	int					GetDebuff(void) const			{ return m_iDebuff; }
	AnimationTimeStamp	GetAnimInfo() const				{ return animInfo; }
	int					GetFacing() const				{ return facing;  }
	bool				GetFlashOn() const				{ return flashOn; }
	bool				GetDamageFlash() const			{ return damageFlash; }
	float				GetFlashDuration() const		{ return flashDuration; }
	float				GetFlashTimer() const			{ return flashTimer; }
	SGD::Point			GetWeaponOffset() const			{ return SGD::Point(m_ptPosition.x - AnimationSystem::GetInstance()->GetLoaded()[animInfo.GetCurrAnimation()].GetFrames()[animInfo.GetCurrFrame()].GetAnchorPoint().x + weaponOffset.x,
		m_ptPosition.y - AnimationSystem::GetInstance()->GetLoaded()[animInfo.GetCurrAnimation()].GetFrames()[animInfo.GetCurrFrame()].GetAnchorPoint().y + weaponOffset.y);
	}
	CollisionData*		GetCollisionData(void)			{ return &collisionNode; }
	float				GetStunTimer()					{ return m_fStunTimer; }
	Emitter* GetEmitter() { return myEmitter; }

	void ClearDebuffs();
	// Mutators:
	void				SetImage(SGD::HTexture	img)			{ m_hImage = img; }
	void				SetVelocity(SGD::Vector	vel) 			{ m_vtVelocity = vel; }
	void				SetSize(SGD::Size size)					{ m_szSize = size; }
	void				SetRotation(float ang)					{ m_fRotation = ang; }
	void				SetMaxSpeed(int speed)					{ m_iMaxSpeed = speed; }
	void				SetAttackRate(float speed)				{ m_fAttackRate = speed; }
	void				SetHealth(int health)					{ m_iHealth = health;	}
	void				SetMaxHealth(int health)				{ m_iMaxHealth = health; }
	void				SetDebuff(int debuff)					{ m_iDebuff = debuff; }
	void				SetAnimInfo(AnimationTimeStamp ATS)		{ animInfo = ATS; }
	void				SetFlashOn(bool on)						{ flashOn = on; }
	void				SetDamageFlash(bool on)					{ damageFlash = on; }
	void				SetFlashDuration(float seconds)			{ flashDuration = seconds; }
	void				SetFlashTimer(float seconds)			{ flashTimer = seconds; }
	void				SetCurrAnimation(string animName)		{ animInfo.SetCurrAnimation(animName);
																	animInfo.SetCurrFrame(0);
																	animInfo.SetTimeOnFrame(0.0f); }
	void				SetCollisionData(SGD::Rectangle collisionRect, SGD::Point pPos, std::string tileType);
	void SetEmitter(Emitter* emit) { myEmitter = emit; }

	//void SetDamageFlash(const bool flash, const float time) { damageFlash = flash; flashDuration = time; }

	void SetFacing(int direction)
	{
		facing = direction;
		animInfo.SetFacing(direction);
	}

	void SetColor(SGD::Color Dolor) { m_cRect = Dolor; }
	void SetWeaponOffset(SGD::Point offset) { weaponOffset = offset; }
	void SetWeaponOffset(float x, float y) { SetWeaponOffset({ x, y }); }

	SGD::Vector GetAiming() const { return aiming; }
protected:
	
	// members:
	SGD::HTexture		m_hImage = SGD::INVALID_HANDLE;	// image handle
	SGD::Point			pastPosition = SGD::Point{ 0, 0 };		// 2D position
	SGD::Point			pastAnchorPoint = SGD::Point{ 0, 0 };
	SGD::Rectangle		pastCollisionRect;
	SGD::Vector			m_vtVelocity = SGD::Vector{ 0, 0 };	// 2D velocity
	SGD::Vector			aiming = { 0, 0 };		//where the player is currently aiming
	float				m_fRotation = 0.0f;		// angle in radians
	int					m_iMaxSpeed = 0;		//Maximum Speed
	int					m_iHealth = 0;			//Current Health
	int					m_iMaxHealth = 0;		//Maximum Health
	int					m_iDebuff = 0;			// Current Debuff Applied (Enum?)
	float				m_fStunTimer = 0;		//Stun Timer
	float				m_fDotTimer = 0;		//DOT timer
	float				m_fDotDmgTimer = 0;		//Do Damage if Dot timer > 0 nd dmg timer reaches 0
	float				m_fSlowTimer = 0;		//Slow Timer
	float				m_fAttackRate = 0.0f;		//Attack SPeed/fire rate
	float				damageTimer = 0.0f; // invulnerability timer

	// used for character collision
	float dt;

	SGD::Rectangle		pastRect;

	//Add an Active rect for Damage Collision Events

	CollisionData		collisionNode;

	SGD::Color			m_cRect = SGD::Color{ 255, 0, 255 };
	int facing = 1;

	bool damageFlash = false;
	MovingObjectType moType;
	AnimationTimeStamp animInfo;

	// personal emitter for this projectile
	Emitter* myEmitter = nullptr;

private:
	/**********************************************************/
	// reference count
	unsigned int		m_unRefCount = 1;	// calling 'new' gives the prime reference

	float flashDuration;//how long the object will flash for
	float flashTimer = 0.1f;//how long each flash lasts
	bool flashOn = true;
	SGD::Point weaponOffset = { 0, 0 };
	SGD::Color flashColor = { 255, 0, 0 };

public:
	


};

